/*
 * Control.cpp
 *
 *  Created on: 24-11-2010
 *      Author: Przemek
 */

#include "gui/Control.hpp"
#include "gui/UIManager.hpp"
#include "gui/ClipArea.hpp"
#include "utils/VectorUtils.hpp"
#include "pch.hpp"
using namespace std;

Control::Control() :
	opaque(true)
{

}

const geometry::Rectangle& Control::getBounds() const
{
	return bounds;
}

void Control::setBounds(const geometry::Rectangle& bounds)
{
	this->bounds = bounds;
}

const Vector& Control::getPosition() const
{
	return bounds.getPosition();
}

void Control::setPosition(const Vector& point)
{
	bounds.setPosition(point);
}

const Dimension& Control::getSize() const
{
	return bounds.getSize();
}

void Control::setSize(const Dimension& size)
{
	bounds.setSize(size);
}

void Control::addManagedMouseListener(MouseListener* mouseListener)
{
	boost::shared_ptr<MouseListener> toAdd = boost::shared_ptr<MouseListener>(mouseListener);
	if(VectorUtils::contains<boost::shared_ptr<MouseListener> >(managedMouseListeners, toAdd)
			== false)
	{
		managedMouseListeners.push_back(toAdd);
	}
}

void Control::addMouseListener(MouseListener* mouseListener)
{
	if(VectorUtils::contains<MouseListener*>(mouseListeners, mouseListener) == false)
	{
		mouseListeners.push_back(mouseListener);
	}
}

void Control::addManagedKeyListener(KeyListener* keyListener)
{
	boost::shared_ptr<KeyListener> toAdd = boost::shared_ptr<KeyListener>(keyListener);
	if(VectorUtils::contains<boost::shared_ptr<KeyListener> >(managedKeyListeners, toAdd) == false)
	{
		managedKeyListeners.push_back(toAdd);
	}
}

void Control::addKeyListener(KeyListener* keyListener)
{
	if(VectorUtils::contains<KeyListener*>(keyListeners, keyListener) == false)
	{
		keyListeners.push_back(keyListener);
	}
}

void Control::mousePressed(const MouseListener::EventArguments& arguments)
{
	notifyMousePressed(arguments);
}

void Control::mouseEntered()
{
	notifyMouseEntered();
}

void Control::mouseExited()
{
	notifyMouseExited();
}

void Control::mouseMoved(const MouseListener::EventArguments& arguments)
{
	notifyMouseMoved(arguments);
}

void Control::mouseDragged(const MouseListener::EventArguments& arguments)
{
	notifyMouseDragged(arguments);
}

void Control::mouseReleased(const MouseListener::EventArguments& arguments)
{
	notifyMouseReleased(arguments);
}

bool Control::isOpaque()
{
	return opaque;
}

void Control::setOpaque(bool opaque)
{
	this->opaque = opaque;
}

void Control::keyPressed(const KeyListener::EventArguments& arguments)
{
	notifyKeyPressed(arguments);
}

Control::~Control()
{
}

void Control::notifyMousePressed(const MouseListener::EventArguments& arguments)
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mousePressed(arguments);
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mousePressed(arguments);
				}
}

void Control::notifyMouseEntered()
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mouseEntered();
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mouseEntered();
				}
}

void Control::notifyMouseExited()
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mouseExited();
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mouseExited();
				}
}

void Control::notifyMouseMoved(const MouseListener::EventArguments& arguments)
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mouseMoved(arguments);
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mouseMoved(arguments);
				}
}

void Control::notifyMouseDragged(const MouseListener::EventArguments& arguments)
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mouseDragged(arguments);
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mouseDragged(arguments);
				}
}

void Control::notifyMouseReleased(const MouseListener::EventArguments& arguments)
{
	BOOST_FOREACH(boost::shared_ptr<MouseListener> listener, managedMouseListeners)
				{
					listener->mouseReleased(arguments);
				}

	BOOST_FOREACH(MouseListener* listener, mouseListeners)
				{
					listener->mouseReleased(arguments);
				}
}

void Control::notifyKeyPressed(const KeyListener::EventArguments& arguments)
{
	BOOST_FOREACH(boost::shared_ptr<KeyListener> listener, managedKeyListeners)
				{
					listener->keyPressed(arguments);
				}

	BOOST_FOREACH(KeyListener* listener, keyListeners)
				{
					listener->keyPressed(arguments);
				}
}

Vector Control::getCenteredTextLeftCornerPosition(const string& text) const
{
	geometry::Rectangle normalisedBounds = bounds;
	normalisedBounds.setPosition(Vector(0, 0));
	const Dimension textBounds = UIManager::getInstance().getGUIFont().measureTextSize(text);

	return normalisedBounds.getLeftCornerForCenteredDimension(textBounds);
}

void Control::drawControl(Control& control, const ClipArea& clipArea)
{
	glPushMatrix();
	translateOglCoordinatesToControlCoordinates(control);
	control.draw(clipArea);
	glPopMatrix();
}

void Control::translateOglCoordinatesToControlCoordinates(const Control& control) const
{
	const Vector& position = control.getPosition();
	// weird casting in order fonts not to blur
	const int x = static_cast<int> (position.getX());
	const int y = static_cast<int> (position.getY());
	glTranslatef(static_cast<float> (x), static_cast<float> (y), 0.0f);
}

MouseListener::EventArguments Control::translateEventPointToControlPoint(
		const MouseListener::EventArguments& arguments, const Control& control) const
{
	MouseListener::EventArguments translatedArguments(arguments);
	translatedArguments.setPoint(arguments.getPoint() - control.getPosition());

	return translatedArguments;
}

